/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 * Origin source from MaNGOS(GPL2).
 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
 */

#include "Map.h"
#include "Player.h"
#include "MapReference.h"
#include "MapRefManager.h"
#include "GridNotifier.h"
#include "TypeContainerVisitor.h"
#include "GridDefine.h"
#include "Cell.h"

namespace PQServiceCore
{
	void Map::Update(const uint32 deltaT)
	{
		/// update players at tick
		for(_mapRefIter = _mapRefManager.begin(); _mapRefIter != _mapRefManager.end(); ++_mapRefIter){
			Player* player = _mapRefIter->getSource();
			if(player && player->isInWorld()){
				player->Update(deltaT);
			}
		}

		/// update active cells around players and active objects
		resetMarkedCells();
		
		ObjectUpdater updater(deltaT);
		//for creature
		TypeContainerVisitor<ObjectUpdater,GridTypeMapContainer> grid_object_update(updater);

		//for pets
		TypeContainerVisitor<ObjectUpdater,WorldTypeMapContainer> world_object_update(updater);

		// the player iterator is stored in the map object
		// to make sure calls to Map::Remove don't invalidate it
		for(_mapRefIter = _mapRefManager.begin(); _mapRefIter != _mapRefManager.end(); ++_mapRefIter){
			Player* player=_mapRefIter->getSource();
			if(!player->isInWorld()){
				continue;
			}
			CellPair standing_cell(ComputeCellPair(player->GetPositionX(),player->GetPositionY()));
			
			// Check for correctness of standing_cell, it also avoids problems with update_cell
			if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP){
				continue;
			}

			// the overloaded operators handle range checking
			// so ther's no need for range checking inside the loop
			CellPair begin_cell(standing_cell), end_cell(standing_cell);
			//lets update mobs/objects in ALL visible cells around player!
			//CellArea area = Cell::CalculateCellArea(*player, GetVisibilityDistance());
			//area.ResizeBorders(begin_cell, end_cell);

		}

		/*

		
		for(m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
		{

			

			for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
			{
				for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
				{
					// marked cells are those that have been visited
					// don't visit the same cell twice
					uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
					if(!isCellMarked(cell_id))
					{
						markCell(cell_id);
						CellPair pair(x,y);
						Cell cell(pair);
						cell.data.Part.reserved = CENTER_DISTRICT;
						cell.SetNoCreate();
						cell.Visit(pair, grid_object_update,  *this);
						cell.Visit(pair, world_object_update, *this);
					}
				}
			}
		}

		// non-player active objects
		if(!m_activeNonPlayers.empty())
		{
			for(m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end(); )
			{
				// skip not in world
				WorldObject* obj = *m_activeNonPlayersIter;

				// step before processing, in this case if Map::Remove remove next object we correctly
				// step to next-next, and if we step to end() then newly added objects can wait next update.
				++m_activeNonPlayersIter;

				if(!obj->IsInWorld())
					continue;

				CellPair standing_cell(MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));

				// Check for correctness of standing_cell, it also avoids problems with update_cell
				if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
					continue;

				// the overloaded operators handle range checking
				// so ther's no need for range checking inside the loop
				CellPair begin_cell(standing_cell), end_cell(standing_cell);
				begin_cell << 1; begin_cell -= 1;               // upper left
				end_cell >> 1; end_cell += 1;                   // lower right

				for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
				{
					for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
					{
						// marked cells are those that have been visited
						// don't visit the same cell twice
						uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
						if(!isCellMarked(cell_id))
						{
							markCell(cell_id);
							CellPair pair(x,y);
							Cell cell(pair);
							cell.data.Part.reserved = CENTER_DISTRICT;
							cell.SetNoCreate();
							cell.Visit(pair, grid_object_update,  *this);
							cell.Visit(pair, world_object_update, *this);
						}
					}
				}
			}
		}

		// Send world objects and item update field changes
		SendObjectUpdates();

		// Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
		// This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
		if (!IsBattleGroundOrArena())
		{
			for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )
			{
				NGridType *grid = i->getSource();
				GridInfo *info = i->getSource()->getGridInfoRef();
				++i;                                                // The update might delete the map and we need the next map before the iterator gets invalid
				MANGOS_ASSERT(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE);
				sMapMgr.UpdateGridState(grid->GetGridState(), *this, *grid, *info, grid->getX(), grid->getY(), t_diff);
			}
		}

		///- Process necessary scripts
		if (!m_scriptSchedule.empty())
			ScriptsProcess();
			*/
	}



}

